#include <QSettings>
#include <QNetworkProxy>
#include "log.h"
#include "cookiestorage.h"

#include "httpconnector.h"

namespace Wishmaster {

HttpConnector::HttpConnector(QObject *parent) : Connector(parent),
	m_mainQueueLength(20),
	m_cookieStorage(0)
{
	m_networkManager = new QNetworkAccessManager(this);

	QSettings settings;
	QString proxyhost = settings.value("connection/proxyhost").toString();
	unsigned int proxyport = settings.value("connection/proxyport").toUInt();
	if(!proxyhost.isEmpty() && proxyport != 0)
	{
		QString proxyuser = settings.value("connection/proxyuser").toString();
		QString proxypass = settings.value("connection/proxypass").toString();
		m_networkManager->setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, proxyhost, proxyport, proxyuser, proxypass));
	}
}

HttpConnector::~HttpConnector()
{
	delete m_networkManager;
}

void HttpConnector::queue(const RequestPtr& request)
{
	HttpRequestPtr rq = request.dynamicCast<HttpRequest>();
	if(!rq)
		return;
	log(llDebug, "HttpConnector::queue: %d/%d/%d", m_pending.size(), m_processing.size(), m_done.size());
	clearDoneQueue();
	if((int)m_processing.size() < m_mainQueueLength)
	{
		startRequest(rq);
	}
	else
	{
		m_pending.push_back(rq);
	}
}

void HttpConnector::queueFirst(const RequestPtr& request)
{
	HttpRequestPtr rq = request.dynamicCast<HttpRequest>();
	if(!rq)
		return;
	clearDoneQueue();
	if((int)m_processing.size() < m_mainQueueLength)
	{
		startRequest(rq);
	}
	else
	{
		m_pending.push_front(rq);
	}
}

void HttpConnector::clearDoneQueue()
{
	m_done.clear();
}

void HttpConnector::startRequest(const HttpRequestPtr& request)
{
	m_processing.push_back(request);
	request->perform();
}

void HttpConnector::requestFinished(int id, bool error)
{
	for(listRequest::iterator it = m_processing.begin(); it != m_processing.end(); ++it)
	{
		if((*it)->id() == id)
		{
			//if(!(*it)->redirect())
			{
				m_done.push_back(*it);
				m_processing.erase(it);
			}
			break;
		}
	}
	if((int)m_processing.size() < m_mainQueueLength)
	{
		if(!m_pending.empty())
		{
			HttpRequestPtr request = m_pending.front();
			if(request)
			{
				startRequest(request);
				m_pending.pop_front();
			}
		}
	}
}

RequestPtr HttpConnector::makeRequest(const QString& host, const QString& path, const QString& method)
{
	QString p = path;
	if(!p.startsWith('/'))
		p.prepend('/');
	if(host.startsWith("http://"))
		return HttpRequestPtr(new HttpRequest(this, QUrl(host + p), method));
	else
		return HttpRequestPtr(new HttpRequest(this, QUrl("http://" + host + p), method));
}

HttpRequestPtr HttpConnector::makeHttpRequest(const QString& host, const QString& path,
									   const QString& method)
{
	return makeRequest(host, path, method).dynamicCast<HttpRequest>();
}

void HttpConnector::connectRequest(QObject* eventReceiver, const char* resultSlot, const char* progressSlot, const RequestPtr& request)
{
	if(progressSlot)
		QObject::connect(request.data(), SIGNAL(progress(int, int)), eventReceiver, progressSlot);
	if(resultSlot)
		QObject::connect(request.data(), SIGNAL(result(RequestPtr, const QByteArray&)), eventReceiver, resultSlot);
}

RequestPtr HttpConnector::request(int id)
{
	for(listRequest::iterator it = m_processing.begin(); it != m_processing.end(); ++it)
	{
		if((*it)->id() == id)
			return (*it);
	}
	for(listRequest::iterator it = m_done.begin(); it != m_done.end(); ++it)
	{
		if((*it)->id() == id)
			return (*it);
	}
	for(queueRequest::iterator it = m_pending.begin(); it != m_pending.end(); ++it)
	{
		if((*it)->id() == id)
			return (*it);
	}
	return RequestPtr();
}

void HttpConnector::dequeue(int id)
{
	for(listRequest::iterator it = m_processing.begin(); it != m_processing.end(); ++it)
	{
		if((*it)->id() == id)
		{
			m_processing.erase(it);
			return;
		}
	}
	for(queueRequest::iterator it = m_pending.begin(); it != m_pending.end(); ++it)
	{
		if((*it)->id() == id)
		{
			m_pending.erase(it);
			return;
		}
	}
	if((int)m_processing.size() < m_mainQueueLength)
	{
		if(!m_pending.empty())
		{
			HttpRequestPtr request = m_pending.front();
			if(request)
			{
				startRequest(request);
				m_pending.pop_front();
			}
		}
	}
}

void HttpConnector::setCookieStorage(CookieStorage* storage)
{
	m_cookieStorage = storage;
}

CookieStorage* HttpConnector::cookieStorage()
{
	return m_cookieStorage;
}

} // namespace Wishmaster
